package org.example.new_hbps_backend_reconstruction.service;

/**
 * @author 丁利军
 * @date 2025年10月16日 15:15
 * @description 批量向腕表推送消息的服务类
 */



import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.new_hbps_backend_reconstruction.common.results.R;
import org.example.new_hbps_backend_reconstruction.dto.BatchNotifyByUidsReq;
import org.example.new_hbps_backend_reconstruction.dto.BatchNotifyReq;
import org.example.new_hbps_backend_reconstruction.entity.PatientDeviceEntity;
import org.example.new_hbps_backend_reconstruction.mapper.PatientDeviceMapper;

import org.example.new_hbps_backend_reconstruction.utils.HTTPUtils;

import org.example.new_hbps_backend_reconstruction.utils.SignUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.util.MultiValueMap;

import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WatchNotifyService {

    private static final String BATCH_NOTIFY_URL = "https://open.heart-forever.com/api/ext/batchNotify";
    private static final String GET_TOKEN_URL   = "https://open.heart-forever.com/api/ext/getToken";

    private final HTTPUtils httpUtils;
    private final PatientDeviceMapper patientDeviceMapper;

    private final String appid;
    private final String secret;

    /** 平台 access_token（服务端用） */
    private String accessToken;

    public WatchNotifyService(HTTPUtils httpUtils,
                              PatientDeviceMapper patientDeviceMapper,
                              @Value("${hardware.appid}") String appid,
                              @Value("${hardware.sec}") String secret) {
        this.httpUtils = httpUtils;
        this.patientDeviceMapper = patientDeviceMapper;
        this.appid = appid;
        this.secret = secret;
    }

    @PostConstruct
    public void init() {
        this.accessToken = fetchAccessToken();
    }

    /** 对外：直接 extUserIds 推送 */
    public R<?> batchNotify(BatchNotifyReq req) {
        if (!StringUtils.hasText(req.getExtUserIds())) {
            return R.failed("extUserIds 不能为空");
        }
        if (!StringUtils.hasText(req.getTitle()) || !StringUtils.hasText(req.getContent())) {
            return R.failed("title 与 content 不能为空");
        }

        Map<String, Object> body = buildBody(
                req.getExtUserIds(),
                req.getTitle(),
                req.getContent(),
                nz(req.getIsVibrationReminder()),
                nz(req.getIsBuzzReminder()),
                nz(req.getIsNeedConfirm()),
                nz(req.getDurationOfMsgBox())
        );

        JSONObject resp = postWithAccessToken(BATCH_NOTIFY_URL, body);
        return toR(resp, "批量推送");
    }

    /** 对外：uid 转 extUserIds 后推送 */
    public R<?> batchNotifyByUids(BatchNotifyByUidsReq req) {
        if (req.getUids() == null || req.getUids().isEmpty()) {
            return R.failed("uids 不能为空");
        }
        // 将 uid -> pddId（extUserId）
        List<PatientDeviceEntity> list = patientDeviceMapper.selectList(
                new LambdaQueryWrapper<PatientDeviceEntity>()
                        .in(PatientDeviceEntity::getPatientUid, req.getUids())
        );
        if (list == null || list.isEmpty()) {
            return R.failed("未找到对应设备/用户的三方ID");
        }
        String extUserIds = list.stream()
                .map(PatientDeviceEntity::getPddId)
                .filter(Objects::nonNull)
                .map(String::valueOf)
                .collect(Collectors.joining(","));

        if (!StringUtils.hasText(extUserIds)) {
            return R.failed("目标用户三方ID为空");
        }

        if (!StringUtils.hasText(req.getTitle()) || !StringUtils.hasText(req.getContent())) {
            return R.failed("title 与 content 不能为空");
        }

        Map<String, Object> body = buildBody(
                extUserIds,
                req.getTitle(),
                req.getContent(),
                nz(req.getIsVibrationReminder()),
                nz(req.getIsBuzzReminder()),
                nz(req.getIsNeedConfirm()),
                nz(req.getDurationOfMsgBox())
        );

        JSONObject resp = postWithAccessToken(BATCH_NOTIFY_URL, body);
        return toR(resp, "批量推送");
    }

    // ---------------- internal helpers ----------------

    private Map<String, Object> buildBody(String extUserIds, String title, String content,
                                          Integer isVibrationReminder, Integer isBuzzReminder,
                                          Integer isNeedConfirm, Integer durationOfMsgBox) {
        Map<String, Object> body = new HashMap<>();
        body.put("extUserIds", extUserIds);
        body.put("content", content);
        body.put("title", title);
        body.put("isVibrationReminder", isVibrationReminder);
        body.put("isBuzzReminder", isBuzzReminder);
        body.put("isNeedConfirm", isNeedConfirm);
        body.put("durationOfMsgBox", durationOfMsgBox);
        return body;
        // 例：
        // {
        //   "extUserIds":"idA,idB",
        //   "content":"批量推送内容",
        //   "title":"批量推送测试",
        //   "isVibrationReminder":1,
        //   "isBuzzReminder":1,
        //   "isNeedConfirm":1,
        //   "durationOfMsgBox":1
        // }
    }

    /** 携带 access_token 的 POST；token 失效(10007/10020)自动刷新并重试一次 */
    private JSONObject postWithAccessToken(String url, Map<String, Object> body) {
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        header.add("access_token", accessToken);

        JSONObject resp = httpUtils.post(url, body, header);
        if (resp != null) {
            Integer code = resp.getInteger("code");
            if (code != null && (code == 10007 || code == 10020)) {
                log.warn("access_token 失效，自动刷新后重试一次");
                accessToken = fetchAccessToken();
                MultiValueMap<String, String> newHeader = new LinkedMultiValueMap<>();
                newHeader.add("access_token", accessToken);
                resp = httpUtils.post(url, body, newHeader);
            }
        }
        return resp;
    }

    /** 向平台获取 access_token */
    private String fetchAccessToken() {
        String nonce = UUID.randomUUID().toString();
        long timestamp = System.currentTimeMillis();

        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("signature", SignUtils.sign(appid, nonce, secret, timestamp));
        params.put("nonce", nonce);
        params.put("timestamp", String.valueOf(timestamp));

        JSONObject json = httpUtils.post(GET_TOKEN_URL, params);
        if (json != null && Objects.equals(json.getInteger("code"), 0)) {
            return json.getString("data");
        }
        throw new IllegalStateException("获取 access_token 失败: " + (json == null ? "null" : json.toJSONString()));
    }

    private R<?> toR(JSONObject response, String action) {
        if (response == null) return R.failed(action + "失败：无响应");
        Integer code = response.getInteger("code");
        String msg = response.getString("msg");
        Object data = response.get("data");
        if (Objects.equals(code, 0)) return R.ok(data, action + "成功");
        return R.failed(data, action + "失败：" + msg);
    }

    private static Integer nz(Integer v) { return v == null ? 0 : v; }
}

